#!/usr/bin/env python2.6
# -*- encoding: utf8 -*-

import unittest

import codegen.gen as gen
import util.test_helper as test_helper


__author__ = 'fcamel'


class GenTest(test_helper.AdvancedTestCase):
    def setUp(self):
        self.generator = gen.CodeGenerator()

    def testCreateClass(self):
        actual = self.generator.create_class('Color', ['red', 'green', 'blue'])

        expected = [
            'class Color(object):',
            '    def __init__(self, red, green, blue):',
            '        self.red = red',
            '        self.green = green',
            '        self.blue = blue',
            '',
            '    def __eq__(self, other):',
            '        if not isinstance(other, type(self)):',
            '            return False',
            '        return (self.red == other.red',
            '                and self.green == other.green',
            '                and self.blue == other.blue)',
            '',
            '    def __ne__(self, other):',
            '        return not self == other',
            '',
            '    def __str__(self):',
            '        return "%s, %s, %s" % (self.red, self.green, self.blue)',
            '',
            '    def __cmp__(self, other):',
            '        if not isinstance(other, type(self)):',
            '            return False',
            '        return (cmp(self.red, other.red)',
            '                or cmp(self.green, other.green)',
            '                or cmp(self.blue, other.blue))',
            '',
        ]

        self.assertEquals(len(expected), len(actual))
        for e, a in zip(expected, actual):
            self.assertEquals(e, a)


    def testEq(self):
        actual = self.generator.create_class('Color', ['red', 'green', 'blue'])
        self._execute(actual)

        try:
            c = Color(32, 64, 128)
            c2 = Color(32, 64, 128)
            c3 = Color(255, 64, 128)
        except NameError(e):
            self.fail('Failed to new objects.')

        try:
            self.assertTrue(c == c)
            self.assertTrue(not c != c)
            self.assertTrue(c is not c2)
            self.assertTrue(c == c2)
            self.assertTrue(not c != c2)
            self.assertTrue(not c == c3)
            self.assertTrue(c != c3)
        except NameError(e):
            self.fail('Failed to execute == or !=.')

    def testStr(self):
        actual = self.generator.create_class('Person', ['height', 'name'])
        self._execute(actual)

        p = Person(170, 'John Smith')
        self.assertEquals('170, John Smith', str(p))

    def _execute(self, codes):
        try:
            exec '\n'.join(codes) in globals()
        except Exception, e:
            self.fail('caught an exception when execuing generated codes.')

    def testCmp(self):
        actual = self.generator.create_class('Person', ['height', 'name'])
        self._execute(actual)

        p = Person(170, 'John Smith')
        q = Person(180, 'John Smith')

        self.assertListEquals([p, q], list(sorted([p, q])))
        self.assertListEquals([p, q], list(sorted([q, p])))

        # change the order of p, q to make sure that
        # the previous test is not passed by default comparator.
        q.height = 150

        self.assertListEquals([q, p], list(sorted([p, q])))
        self.assertListEquals([q, p], list(sorted([q, p])))

        # the comparator should consider the second field as well.
        q.height = 170
        q.name = 'Zelda'

        self.assertListEquals([p, q], list(sorted([p, q])))
        self.assertListEquals([p, q], list(sorted([q, p])))

        # change the order of p, q to make sure that
        # the previous test is not passed by default comparator.
        q.height = 170
        q.name = 'Andy'

        self.assertListEquals([q, p], list(sorted([p, q])))
        self.assertListEquals([q, p], list(sorted([q, p])))


if __name__ == '__main__':
    unittest.main()
